package com.autumn.evaluator;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.map.CaseInsensitiveMap;

//
// * 提供函数注册，获取函数、反注册函数等操作
// 

import com.autumn.evaluator.annotation.FunctionRegister;
import com.autumn.evaluator.annotation.ParamRegister;
import com.autumn.evaluator.functions.ArithFunction;
import com.autumn.evaluator.functions.ArrayFunction;
import com.autumn.evaluator.functions.DateTimeFunction;
import com.autumn.evaluator.functions.FinancialFunction;
import com.autumn.evaluator.functions.StatisticsFunction;
import com.autumn.evaluator.functions.SystemFunction;
import com.autumn.evaluator.functions.TextFunction;
import com.autumn.util.ArgumentNullException;
import com.autumn.util.StringUtils;

/**
 * 函数管理
 */
@SuppressWarnings("unchecked")
public final class FunctionManager {

	private static Map<String, Function> functionMap;
	private static Set<String> systemFun;

	/**
	 * 静态实例化
	 */
	static {
		
		FunctionManager.functionMap = new CaseInsensitiveMap();
		FunctionManager.systemFun = new HashSet<>(); // 应修改为不区分大小写，待修改

		ArrayList<Function> funs = FunctionManager.searchFunctions(SystemFunction.class);
		for (Function fun : funs) {
			FunctionManager.systemFun.add(fun.getName());
			FunctionManager.register(fun, true);
		}
		FunctionManager.register(ArithFunction.class);
		FunctionManager.register(ArrayFunction.class);
		FunctionManager.register(DateTimeFunction.class);
		FunctionManager.register(FinancialFunction.class);
		FunctionManager.register(StatisticsFunction.class);
		FunctionManager.register(TextFunction.class);
	}

	/**
	 * 注册函数(如果注册已存在的函则会覆盖,除系统函数外)
	 *
	 * @param name
	 *            函数名称
	 * @param category
	 *            类别
	 * @param caption
	 *            说明
	 * @param call
	 */
	public static Function register(String name, String category, String caption, Call call) {
		if (StringUtils.isNullOrBlank(name)) {
			throw new ArgumentNullException("name");
		}
		if (call == null) {
			throw new ArgumentNullException("call 对象不能为 null");
		}
		Function fun = new Function(name, category, caption, call);
		FunctionManager.register(fun);
		return fun;
	}

	/**
	 * 注册函数(如果注册已存在的函则会覆盖,除系统函数外)
	 *
	 * @param function
	 */
	public static void register(Function function) {
		FunctionManager.register(function, false);
	}

	/**
	 * 注册函数(如果注册已存在的函则会覆盖)
	 *
	 * @param function
	 *            函数
	 * @param isSystem
	 */
	public static void register(Function function, boolean isSystem) {
		if (function == null) {
			throw new ArgumentNullException("function");
		}
		if (!isSystem) {
			if (FunctionManager.systemFun.contains(function.getName())) {
				throw new IllegalArgumentException(String.format("函数 %s 与系统内置函数相同，禁止注册。", function.getName()));
			}
		}
		synchronized (FunctionManager.functionMap) {
			// Object[] Params =
			// function.getCall().Method.GetCustomAttributes(ParamRegister.class, false);

			// Set<Class<?>> types;
			// List<ParamRegister> Params = new ArrayList();
			// try {
			// types =
			// PackageUtils.getPackageAnnotationClass("com.autumn.evaluator.functions",
			// ParamRegister.class);
			// for(Class<?> clazz : types) {
			// if (!clazz.getSimpleName().equalsIgnoreCase(function.getName()))
			// continue;
			// ParamRegister[] annoArray = clazz.getAnnotationsByType(ParamRegister.class);
			// Params.addAll(Arrays.asList(annoArray));
			// }
			// } catch (IOException e) {
			// e.printStackTrace();
			// }

			ParamRegister[] params = function.getFunClass().getAnnotationsByType(ParamRegister.class);

			StringBuilder format = new StringBuilder();
			format.append(function.getName() + "(");
			if (params != null && params.length > 0) {
				// if (Params.size() > 1) {
				// Arrays.sort(Params);
				// }
				for (ParamRegister par : params) {
					// Par._FunctionName = function.getName();
					function.getGetFunParams().add(new FunctionParam(par.orderId(), par.name(), par.caption(),
							new Variant(par.defaultValue()), par.paramType()));
					if (par.defaultValue() != null) {
						format.append(String.format("[%s],", par.name()));
					} else {
						format.append(String.format("%s,", par.name()));
					}
				}
			}
			if (function.getIsDynamicParam()) {
				if (function.getName().equals((new String("Switch")).toUpperCase())) {
					format.append("Case1,Break1,Case2,Break2,...,Default");
				} else {
					String key;
					if (function.getDynamicParamType() == VariantType.STRING) {
						key = "Text";
					} else if (function.getDynamicParamType() == VariantType.BOOLEAN) {
						key = "Logic";
					} else if (function.getDynamicParamType() == VariantType.DATETIME) {
						key = "Date";
					} else if (function.getDynamicParamType() == VariantType.UUID) {
						key = "UUID";
					} else if (function.getDynamicParamType() == VariantType.ARRAY) {
						key = "ARRAY";
					} else if ((VariantType.INTEGER & VariantType.DECIMAL & VariantType.DOUBLE) == function
							.getDynamicParamType()) {
						key = "NUMBER";
					} else {
						key = "Value";
					}
					for (int i = 1; i <= 3; i++) {
						format.append(key + (new Integer(i)).toString() + ",");
					}
					format.append("...");
				}
			} else {
				if (params != null && params.length > 0) {
					format.deleteCharAt(format.length() - 1);
				}
			}
			format.append(")");
			function.format = format.toString();
			functionMap.put(function.getName(), function);
		}
	}

	/**
	 * 注册函数(如果注册已存在的函则会覆盖,除系统函数外)
	 *
	 * @param functions
	 */
	public static void register(Iterable<Function> functions) {
		if (functions == null) {
			throw new ArgumentNullException("functions");
		}
		for (Function fun : functions) {
			FunctionManager.register(fun);
		}
	}

	/**
	 * 注册函数(如果注册已存在的函则会覆盖,除系统函数外)
	 *
	 * @param assembly
	 *            程序集
	 */
	// public static void register(Assembly assembly) {
	// if (assembly == null) {
	// throw new ArgumentNullException("assembly");
	// }
	// var types = assembly.GetTypes();
	// for (var type : types) {
	// FunctionManager.register(type);
	// }
	// }

	/**
	 * 注册函数(如果注册已存在的函则会覆盖,除系统函数外)
	 *
	 * @param functionClassType
	 */
	public static void register(Class<?> functionClassType) {
		FunctionManager.register(FunctionManager.searchFunctions(functionClassType));
	}

	/**
	 * 根据特定的类型,搜索函数集合
	 *
	 * @param functionClassType
	 *            函数类类型
	 */
	public static ArrayList<Function> searchFunctions(Class<?> functionClassType) {
		if (functionClassType == null) {
			throw new ArgumentNullException("functionClassType");
		}

		Set<Class<?>> members = null;
		try {
			members = Utils.getPackageAnnotationClass(functionClassType, FunctionRegister.class);
		} catch (IOException e) {
			e.printStackTrace();
		}

		ArrayList<Function> funs = new ArrayList<>();
		// Object instance = null;
		for (Object m : members.toArray(new Class<?>[members.size()])) {
			FunctionRegister[] registers = ((Class<?>) m).getAnnotationsByType(FunctionRegister.class);
			if (registers != null && registers.length > 0) {
				for (FunctionRegister register : registers) {
					Object callMethod = null;
					try {
						callMethod = ((Class<?>) m).newInstance();
					} catch (InstantiationException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}

					if (callMethod != null) {
						Call call = (Call) ((callMethod instanceof Call) ? callMethod : null);
						if (call != null) {
							funs.add(new Function(register.name(), register.category(), register.caption(), call,
									register.isDynamicParam(), register.dynamicParamType(), register.minParamCount(),
									(Class<?>) m));
						}
					}
				}
			}
		}
		return funs;
	}

	/**
	 * 反注册所有函数,除系统函数外
	 */
	public static void notRegistrationAll() {
		synchronized (FunctionManager.functionMap) {
			if (functionMap.size() > 0) {
				String[] keys = functionMap.keySet().toArray(new String[functionMap.keySet().size()]);

				for (String key : keys) {
					if (!FunctionManager.systemFun.contains(key)) {
						functionMap.remove(key);
					}
				}
			}
		}
	}

	/**
	 * 反注册函数,除系统函数外
	 *
	 * @param name
	 */
	public static boolean notRegistration(String name) {
		Utils.checkNotNullOrEmpty("name", name);
		if (!FunctionManager.systemFun.contains(name)) {
			synchronized (FunctionManager.functionMap) {
				boolean isSuccess = true;
				try {
					functionMap.remove(name);
				} catch (Exception e) {
					isSuccess = false;
				}
				return isSuccess;
			}
		}
		return false;
	}

	/**
	 * 获取函数名是否存在
	 *
	 * @param name
	 *            函数名称
	 */
	public static boolean existFunction(String name) {
		Utils.checkNotNullOrEmpty("name", name);
		synchronized (FunctionManager.functionMap) {
			return functionMap.containsKey(name);
		}
	}

	/**
	 * 获取函数
	 * 
	 * @param name
	 *            名称
	 */
	public static Function getFunction(String name) {
		return functionMap.get(name);
	}

	/**
	 * 获取函数集合
	 * 
	 * @return
	 */
	public static ArrayList<Function> getFunctions() {
		synchronized (FunctionManager.functionMap) {
			ArrayList<Function> funs = new ArrayList<Function>();
			for (Function fun : functionMap.values()) {
				funs.add(fun);
			}
			return funs;
		}
	}

	/**
	 * 获取函数集合
	 * 
	 * @param category
	 *            类别
	 * @return // * @throws System.ArgumentNullException/
	 */
	public static ArrayList<Function> getFunctions(String category) {
		if (category == null) {
			throw new ArgumentNullException("Category");
		}
		synchronized (FunctionManager.functionMap) {
			ArrayList<Function> funs = new ArrayList<Function>();
			for (Function fun : functionMap.values()) {
				if (fun.getCategory().equals(category)) {
					funs.add(fun);
				}
			}
			return funs;
		}
	}

	/**
	 * 获取函数类别集合
	 * 
	 * @return
	 */
	public static ArrayList<String> getCategorys() {
		synchronized (FunctionManager.functionMap) {
			ArrayList<String> ls = new ArrayList<String>();
			for (Function fun : functionMap.values()) {
				if (!ls.contains(fun.getCategory())) {
					ls.add(fun.getCategory());
				}
			}
			return ls;
		}
	}

	/**
	 * 搜索函数
	 * 
	 * @param likeCaption
	 *            包含说明
	 */
	public static ArrayList<Function> findFunctions(String likeCaption) {
		if (likeCaption == null) {
			throw new ArgumentNullException("LikeCaption");
		}
		synchronized (FunctionManager.functionMap) {
			ArrayList<Function> funs = new ArrayList<Function>();
			for (Function fun : functionMap.values()) {
				if (fun.getCaption().toUpperCase().contains(likeCaption.toUpperCase())
						|| fun.getName().toUpperCase().contains(likeCaption.toUpperCase())) {
					funs.add(fun);
				}
			}
			return funs;
		}
	}
}